package com.yalu.file;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.yalu.enmus.CurrencyEnum;
import com.yalu.entity.BillData;
import com.yalu.entity.BillDetailData;
import com.yalu.entity.BillDetailDataExcel;
import com.yalu.util.CommonUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.pdfbox.io.RandomAccessFile;
import org.apache.pdfbox.pdfparser.PDFParser;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.text.PDFTextStripper;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 南洋
 */
@Slf4j
@Component
public class NyPdfRead {

    /**
     * 读PDF文件，使用了pdfbox开源项目
     *
     * @param fileName
     */
    public static void readPdf(String fileName, String year, Map<String, BillData> map) {
        File file = new File(fileName);
        FileInputStream in = null;
        try {
            in = new FileInputStream(fileName);
            // 新建一个PDF解析器对象
            PDFParser parser = new PDFParser(new RandomAccessFile(file, "r"));
            // 对PDF文件进行解析
            parser.parse();
            // 获取解析后得到的PDF文档对象
            PDDocument pdfdocument = parser.getPDDocument();
            int pageSize = pdfdocument.getNumberOfPages();
            Queue<String> nowQueue = new LinkedList<>();
            String lastBalance = "";
            for (int i = 0; i < pageSize; i++) {
                // 新建一个PDF文本剥离器
                PDFTextStripper stripper = new PDFTextStripper();
                // 设置按顺序输出
                stripper.setSortByPosition(true);
                stripper.setStartPage(i + 1);
                stripper.setEndPage(i + 1);
                String lineSepartor = stripper.getLineSeparator();
                // 从PDF文档对象中剥离文本
                String result = stripper.getText(pdfdocument);
                String[] resultArray = result.split(lineSepartor);
                int arrayLength = resultArray.length;
                Queue<BillDetailData> dataQueue = new LinkedList<>();
                int orderNumber = 1;
                for (int y = 0; y < arrayLength; y++) {
                    String lineText = resultArray[y];
                    if (null == lineText || "".equals(lineText.trim()) || lineText.contains("Total")) {
                        continue;
                    }
                    if (lineText.contains("Thank you")) {
                        break;
                    }
                    if (lineText.contains("港元往來 (043-504-0-008447-8)§")) {
                        nowQueue.poll();
                        orderNumber = 1;
                        BillData billData = map.get("HKDCurrent");
                        if (null == billData) {
                            billData = new BillData();
                            billData.setCurrency("HKD");
                            billData.setType("Current");
                            List<BillDetailData> list = new ArrayList<>();
                            billData.setDetailData(list);
                            map.put(billData.getCurrency().concat(billData.getType()), billData);
                        }
                        String key = billData.getCurrency().concat(billData.getType());
                        nowQueue.offer(key);
                    } else if (lineText.contains("人民幣往來 (043-504-0-601111-1)§")) {
                        nowQueue.poll();
                        orderNumber = 1;
                        BillData billData = map.get("RMBCurrent");
                        if (null == billData) {
                            billData = new BillData();
                            billData.setCurrency("RMB");
                            billData.setType("Current");
                            List<BillDetailData> list = new ArrayList<>();
                            billData.setDetailData(list);
                            map.put(billData.getCurrency().concat(billData.getType()), billData);
                        }
                        String key = billData.getCurrency().concat(billData.getType());
                        nowQueue.offer(key);
                    } else if (lineText.contains("人民幣往來 (043-504-0-601111-1)§")) {
                        nowQueue.poll();
                        orderNumber = 1;
                        BillData billData = map.get("RMBCurrent");
                        if (null == billData) {
                            billData = new BillData();
                            billData.setCurrency("RMB");
                            billData.setType("Current");
                            List<BillDetailData> list = new ArrayList<>();
                            billData.setDetailData(list);
                            map.put(billData.getCurrency().concat(billData.getType()), billData);
                        }
                        String key = billData.getCurrency().concat(billData.getType());
                        nowQueue.offer(key);
                    } else if (lineText.contains("港元儲蓄 (043-504-1-025731-4)")) {
                        nowQueue.poll();
                        orderNumber = 1;
                        BillData billData = map.get("HKDSavings");
                        if (null == billData) {
                            billData = new BillData();
                            billData.setCurrency("HKD");
                            billData.setType("Savings");
                            List<BillDetailData> list = new ArrayList<>();
                            billData.setDetailData(list);
                            map.put(billData.getCurrency().concat(billData.getType()), billData);
                        }
                        String key = billData.getCurrency().concat(billData.getType());
                        nowQueue.offer(key);
                    } else if (lineText.contains("港元儲蓄 (043-504-1-025731-4)")) {
                        nowQueue.poll();
                        orderNumber = 1;
                        BillData billData = map.get("HKDSavings");
                        if (null == billData) {
                            billData = new BillData();
                            billData.setCurrency("HKD");
                            billData.setType("Savings");
                            List<BillDetailData> list = new ArrayList<>();
                            billData.setDetailData(list);
                            map.put(billData.getCurrency().concat(billData.getType()), billData);
                        }
                        String key = billData.getCurrency().concat(billData.getType());
                        nowQueue.offer(key);
                    } else {
                        String key = nowQueue.poll();
                        if (null != key) {
                            nowQueue.offer(key);

                            if (null != lineText) {
                                if(lineText.contains("合計")){
                                    continue;
                                }
                                Pattern pattern = Pattern.compile(CommonUtil.AMOUNT_MATCHES);
                                Matcher matcher = pattern.matcher(lineText.replace(",", ""));
                                BillDetailData detailData = new BillDetailData();
                                if (matcher.find()) {
                                    String[] lineTextArray = lineText.split(" ");
                                    int length = lineTextArray.length;
                                    String one = lineTextArray[length - 1].replace(",", "").replace("DR", "").replace("OR", "");
                                    String transactionDetails = handleTransactionType(lineText);
                                    BillDetailData detailDataQueue = dataQueue.poll();
                                    dataQueue.offer(detailDataQueue);
                                    if (null != detailDataQueue) {
                                        dataQueue.poll();
                                        BeanUtils.copyProperties(detailDataQueue, detailData);
                                        dataQueue.offer(detailData);
                                    }
                                    detailData.setDate(length > 0 ? lineTextArray[0] : "");
                                    detailData.setTransactionDetails(length > 2 ? lineTextArray[2] : "");
                                    detailData.setOrderNumber(orderNumber);
                                    int isTwo = length - 2;
                                    String two = "";
                                    if (isTwo >= 0) {
                                        two = lineTextArray[isTwo].replace(",", "");
                                        if(!StringUtils.hasText(two)){
                                            two = length-3>=0?lineTextArray[length-3].replace(",", ""):"";
                                        }
                                    }
                                    handleAmount(lineTextArray, one, transactionDetails, detailData, two, lastBalance);
                                    BillData billData = map.get(key);
                                    if (null != billData && StringUtils.hasText(detailData.getTransactionDetails()) && (StringUtils.hasText(detailData.getBalance()) || StringUtils.hasText(detailData.getDeposit()) || StringUtils.hasText(detailData.getWithdrawal()))) {
                                        billData.getDetailData().add(detailData);
                                        dataQueue.poll();
                                        dataQueue.offer(detailData);
                                        lastBalance = detailData.getBalance();
                                    }
                                    orderNumber++;
                                }else{
                                    log.warn("未找到金额：{}",lineText);
                                    if (lineText.matches("[A-Z]{3}") && CurrencyEnum.isCurrency(lineText)) {
                                        String currency = lineText;
                                        detailData = new BillDetailData();
                                        BillData billData = new BillData();
                                        billData.setCurrency(currency);
                                        billData.setType(key.substring(3));
                                        key = billData.getCurrency().concat(billData.getType());
                                        BillData nowBillData = map.get(key);
                                        if (null == nowBillData) {
                                            orderNumber = 1;
                                            List<BillDetailData> list = new ArrayList<>();
                                            billData.setDetailData(list);
                                            map.put(key, billData);
                                        }else{

                                        }
                                        dataQueue.poll();
                                        nowQueue.poll();
                                        nowQueue.offer(key);
                                        dataQueue.offer(detailData);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        } catch (Exception e) {
            System.out.println("读取PDF文件" + file.getAbsolutePath() + "生失败！" + e);
            e.printStackTrace();
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e1) {
                }
            }
        }
    }

    /**
     * 处理交易类型
     *
     * @param lineText
     * @return
     */
    private static String handleTransactionType(String lineText) {
        String transactionDetails = null;
        if (lineText.contains("承前結餘")) {
            transactionDetails = "承前結餘";
        } else if (lineText.contains("CDM DEP")) {
            transactionDetails = "CDM DEP";
        } else if (lineText.contains("CBS TRANSFER")) {
            transactionDetails = "CBS TRANSFER";
        } else if (lineText.contains("CHATS")) {
            transactionDetails = "CHATS";
        } else if (lineText.contains("今期結餘")) {
            transactionDetails = "今期結餘";
        } else if (lineText.contains("利息")) {
            transactionDetails = "利息";
        } else if (lineText.contains("REMIT OUT")) {
            transactionDetails = "REMIT OUT";
        } else if (lineText.contains("REMIT IN")) {
            transactionDetails = "REMIT IN";
        } else if (lineText.contains("RETURN REMIT")) {
            transactionDetails = "RETURN REMIT";
        }

        return transactionDetails;
    }

    /**
     * 处理金额
     *
     * @param lineTextArray
     * @param one
     * @param transactionDetails
     * @param detailData
     * @param two
     */
    private static void handleAmount(String[] lineTextArray, String one, String transactionDetails, BillDetailData detailData, String two, String lastBalance) {
        detailData.setBalance(null);
        detailData.setWithdrawal(null);
        detailData.setDeposit(null);
        String balance = "";
        String withdrawal = "";
        String deposit = "";
        if (StringUtils.hasText(one) && StringUtils.hasText(two) && StringUtils.hasText(lastBalance)) {
            if (one.matches(CommonUtil.AMOUNT_MATCHES) && two.matches(CommonUtil.AMOUNT_MATCHES) && lastBalance.matches(CommonUtil.AMOUNT_MATCHES)) {
                balance = one;
                BigDecimal balanceDecimal = new BigDecimal(balance);
                BigDecimal lastBalanceDecimal = new BigDecimal(lastBalance);
                BigDecimal twoDecimal = new BigDecimal(two);
                if (balanceDecimal.compareTo(lastBalanceDecimal.add(twoDecimal)) == 0) {
                    deposit = two;
                } else if (balanceDecimal.compareTo(lastBalanceDecimal.subtract(twoDecimal)) == 0) {
                    withdrawal = two;
                }
            } else if (one.matches(CommonUtil.AMOUNT_MATCHES)) {
                balance = one;
            }
        } else {
            balance = one;
        }
        if (StringUtils.hasText(balance) && balance.matches(CommonUtil.AMOUNT_MATCHES)) {
            detailData.setBalance(balance);
        }
        if (StringUtils.hasText(withdrawal) && withdrawal.matches(CommonUtil.AMOUNT_MATCHES)) {
            detailData.setWithdrawal(withdrawal);
        }
        if (StringUtils.hasText(deposit) && deposit.matches(CommonUtil.AMOUNT_MATCHES)) {
            detailData.setDeposit(deposit);
        }

        if (null != transactionDetails && !StringUtils.hasText(detailData.getTransactionDetails())) {
            detailData.setTransactionDetails(transactionDetails);
        }
    }


    /**
     * 测试pdf文件的创建
     *
     * @param args
     */
    public static void main(String[] args) {
        String filePath = "D://yalu//monthly//";  //这里先手动把绝对路径的文件夹给补上。
        LinkedList<String> filePaths = new LinkedList<>();
        recursionFile(filePath, filePaths);
        System.out.println("文件数量：" + filePaths.size());
        Map<String, BillData> map = new HashMap<>();
        String year = "";
        for (String fileName : filePaths) {
            int lastIndex = fileName.lastIndexOf("\\");
            year = fileName.substring(lastIndex + 1, lastIndex + 5);
            readPdf(fileName, year, map);
        }
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
        String time = LocalDateTime.now().format(dtf);
        String outFileName = "D:\\yalu\\" + year + "年_月结单_南洋_" + time.substring(time.length() - 6) + ".xlsx";
        writerFils(map, outFileName);
    }

    /**
     * 写入文件
     *
     * @param map
     * @param outFileName
     */
    public static void writerFils(Map<String, BillData> map, String outFileName) {
        try {
            ExcelWriter excelWriter = EasyExcel.write(outFileName, BillDetailDataExcel.class).build();
            for (String key : map.keySet()) {
                BillData billData = map.get(key);
                String sheetName = "1";
                if ("Savings".equals(billData.getType())) {
                    sheetName = "月结单（" + billData.getCurrency() + "）";
                } else if ("Current".equals(billData.getType())) {
                    sheetName = "资金往来（" + billData.getCurrency() + "）";
                }
                BigDecimal depositSum = new BigDecimal(0);
                BigDecimal withdrawalSum = new BigDecimal(0);
                List<BillDetailDataExcel> list = new ArrayList<>(billData.getDetailData().size());
                for (BillDetailData billDetailData : billData.getDetailData()) {
                    BillDetailDataExcel billDetailDataExcel = new BillDetailDataExcel();
                    BeanUtils.copyProperties(billDetailData, billDetailDataExcel);
                    if (StringUtils.hasText(billDetailData.getDeposit())) {
                        depositSum = depositSum.add(new BigDecimal(billDetailData.getDeposit()));
                    }
                    if (StringUtils.hasText(billDetailData.getWithdrawal())) {
                        withdrawalSum = withdrawalSum.add(new BigDecimal(billDetailData.getWithdrawal()));
                    }
                    log.info("数据：{}",billDetailDataExcel);
                    list.add(billDetailDataExcel);
                }
                if (0 < list.size()) {
                    BillDetailDataExcel firstData = list.stream().findFirst().get();
                    String balance = firstData.getBalance();
                    BigDecimal balanceDecimal = new BigDecimal(0);
                    if (StringUtils.hasText(balance)) {
                        if (StringUtils.hasText(firstData.getDeposit()) || StringUtils.hasText(firstData.getDeposit())) {
                            balance = "0";
                        } else {
                            balanceDecimal = balanceDecimal.add(new BigDecimal(balance));
                        }
                    }
                    balanceDecimal = balanceDecimal.add(depositSum).subtract(withdrawalSum);
                    BillDetailDataExcel billDetailDataExcel = new BillDetailDataExcel();
                    billDetailDataExcel.setDate("智能校对助手校对结果");
                    billDetailDataExcel.setTransactionDetails("上期结余：" + balance);
                    billDetailDataExcel.setDeposit("总收入：" + depositSum.toString());
                    billDetailDataExcel.setWithdrawal("总支出：" + withdrawalSum.toString());
                    billDetailDataExcel.setBalance(balanceDecimal.toString());
                    list.add(billDetailDataExcel);
                }
                WriteSheet writeSheet = EasyExcel.writerSheet(sheetName).build();
                excelWriter.write(list, writeSheet);
            }
            // 千万别忘记finish 会帮忙关闭流
            excelWriter.finish();
        } catch (Exception e) {
            log.error("文件写入失败：" , e);
        }
    }

    /**
     * 递归文件
     *
     * @param path
     * @param filePaths
     */
    public static void recursionFile(String path, LinkedList<String> filePaths) {
        if (StringUtils.hasText(path)) {
            File file = new File(path);
            for (File f : file.listFiles()) {
                if (f.isDirectory()) {
                    recursionFile(f.getPath(), filePaths);
                } else {
                    if (f.getPath().contains(".pdf")) {
                        filePaths.add(f.getPath());
                    }
                }
            }
        }
    }

}
